#include <stdio.h>
#include <string.h>
#include "ledmatrix.h"
#include "ascii.h"

#include "matrix_16_32.h"

#define MAX_LINE_LENGTH (32*5)
enum {
    MATRIX_SHIFT_RIGHT = 0x01,
    MATRIX_SHIFT_LEFT = 0x02,
    MATRIX_SHIFT_UP = 0x04,
    MATRIX_SHIFT_DOWN = 0x08,
};
static char matrix[MATRIX_WEIGHT][MATRIX_HEIGHT/8];
static int matrix_ix[MATRIX_HEIGHT/8] = {0};
static int matrix_iy = 0;
static char lines[MATRIX_HEIGHT/8][MAX_LINE_LENGTH]={{0}};
static int  ilines[MATRIX_HEIGHT/8]={0};
static int  llines[MATRIX_HEIGHT/8]={0};
static int  slines[MATRIX_HEIGHT/8]={0};
static int matrix_shift = MATRIX_SHIFT_RIGHT | MATRIX_SHIFT_LEFT;
int matrix_init(void)
{
    memset(matrix,0, sizeof(matrix));
    return 0;
}

int matrix_display(void)
{
    int i,j;
    int matrix_x = 0;
#if 0
    printf("\033[2J");
    for(i = 0; i < MATRIX_WEIGHT; i++)
        printf("-");
    printf("\n");
    for( i = matrix_iy; i < MATRIX_HEIGHT; i++)
    {
        printf("|");
        matrix_x = matrix_ix[(i)/8];
        for(j = matrix_x; j < MATRIX_WEIGHT; j++)
        {
            if((matrix[j][i/8]>>(i&0x07))&0x01)
                printf("*");
            else
                printf(" ");
        }
        for(j = 0; j < matrix_x; j++)
        {
            if((matrix[j][i/8]>>(i&0x07))&0x01)
                printf("*");
            else
                printf(" ");
        }
        //! TODO Latch
        printf("|\n");
    }
    for( i = 0; i < matrix_iy; i++)
    {
        printf("|");
        matrix_x = matrix_ix[(i)/8];
        for(j = matrix_x; j < MATRIX_WEIGHT; j++)
        {
            if((matrix[j][i/8]>>(i&0x07))&0x01)
                printf("*");
            else
                printf(" ");
        }
        for(j = 0; j < matrix_x; j++)
        {
            if((matrix[j][i/8]>>(i&0x07))&0x01)
                printf("*");
            else
                printf(" ");
        }
        //! TODO Latch
        printf("|\n");
    }
    for(i = 0; i < MATRIX_WEIGHT; i++)
        printf("-");
    printf("\n");
#endif
    for(j = 0; j < MATRIX_WEIGHT; j++) {
        row_serial_to_parallel(matrix[j][0] | (matrix[j][1] << 8));
        red_column_serial_to_parallel(1<<j);
        green_column_serial_to_parallel(1<<j);
    }
    return 0;
}
int matrix_set_pixel(int x, int y)
{
    int i = 0, j = 0;
    if(x >= MATRIX_WEIGHT || y >= MATRIX_WEIGHT)
        return -1;
    j = (y + matrix_iy)%MATRIX_HEIGHT;
    i = (x + matrix_ix[j/8])%MATRIX_WEIGHT;
    matrix[i][j/8] |= 1 <<(j&0x07);
    return 0;
}
int matrix_clr_pixel(int x, int y)
{
    int i = 0, j = 0;
    if(x >= MATRIX_WEIGHT || y >= MATRIX_WEIGHT)
        return -1;
    j = (y + matrix_iy)%MATRIX_HEIGHT;
    i = (x + matrix_ix[j/8])%MATRIX_WEIGHT;
    matrix[i][j/8] &= ~(1 <<(j&0x07));
    return 0;
}
int matrix_set_iy(int i)
{
    if(i < 0)
        return -1;
    matrix_iy = (matrix_iy + i)%MATRIX_HEIGHT;
    return 0;
}
int matrix_set_ix(int line, int i)
{
    if(i < 0)
        return -1;
    matrix_ix[line] = (matrix_ix[line] + i)%MATRIX_WEIGHT;
    return 0;
}
int matrix_set_data(int x, int y, unsigned char data)
{
    int i = 0, j = 0;
    if(x >= MATRIX_WEIGHT || y >= MATRIX_WEIGHT)
        return -1;
    j = (y + matrix_iy)%MATRIX_HEIGHT;
    i = (x + matrix_ix[j/8])%MATRIX_WEIGHT;
    matrix[i][j/8] &= ~(0xFF <<(j&0x07));
    matrix[i][j/8] |= (data <<(j&0x07));
    if(j&0x07)
    {
        j = (y + 8 + matrix_iy)%MATRIX_HEIGHT;
        i = (x + matrix_ix[j/8])%MATRIX_WEIGHT;
        matrix[i][j/8] &= ~(0xFF >>(8-(j&0x07)));
        matrix[i][j/8] |= (data >>(8-(j&0x07)));
    }
    return 0;
}

int matrix_putchar(int x, int y, unsigned char data)
{
    int i = 0;
    int k = (int)data - START_ASCII;
    for(i = 0; i < 6; i++)
    {
        if(matrix_set_data(i+x,y,ascii_tbl[k][i]) < 0)
            return i;
    }
    return i;
}
int matrix_putstring(int x, int y, char *data)
{
    int i = 0, j = 0, k = 0, m = 0;
#if 1
    while(data[i] != '\0')
    {
        k = matrix_putchar(x+j,y,data[i]);
        //printf("k=%d",k);
        j += k;
        i++;
    }
    ilines[y/8] = x+j-1;
    //printf("AA=%d\n",ilines[y/8]);
    //return j;
#endif
    i = 0;
    while(data[i] != '\0')
    {
        k = data[i] - START_ASCII;
        for(j = 0; j < 6; j++)
        {
            lines[y/8][x++] = ascii_tbl[k][j];
            if(x >= MAX_LINE_LENGTH)
            {
                llines[y/8] = x;
                return (i);
            }
        }
        //printf("%c",data[i]);
        i++;
    }
    llines[y/8] = x;
    //printf("BB=%d\n",llines[y/8]);
    return i;
}
int matrix_clear(void)
{
    int i = 0;
    memset(matrix,0, sizeof(matrix));
    matrix_iy = 0;
    for(i = 0; i < MATRIX_HEIGHT/8; i++)
    {
        matrix_ix[i] = 0;
    }
    return 0;
}

void matrix_loop(void)
{
    int k =0;
    matrix_display();
    if(matrix_shift & MATRIX_SHIFT_UP)
    {
        matrix_set_iy(1);
    }else
    if(matrix_shift == MATRIX_SHIFT_DOWN)
    {
        matrix_set_iy(MATRIX_HEIGHT-1);
    }else
    {
    if(matrix_shift & MATRIX_SHIFT_RIGHT)
    {
        //printf("%2X",lines[0][ilines[0]]);
        matrix_set_ix(1,MATRIX_WEIGHT-1);
        #if 1
        k = ilines[1]- MATRIX_WEIGHT;
        if(k < 0) k += llines[1];
        matrix_set_data(0,8,lines[1][k]);
        ilines[1]--;
        if(ilines[1] < 0)
            ilines[1] =  llines[1] - 1;
        #endif
        //(matrix_ix[0] = (matrix_ix[0] + 1)%MATRIX_WEIGHT;
    }
    if(matrix_shift & MATRIX_SHIFT_LEFT)
    {
        matrix_set_data(0,0,lines[0][ilines[0]]);
        ilines[0]++;
        if(ilines[0] >= llines[0] && ilines[0] >= MATRIX_WEIGHT)
            ilines[0] = 0;
        matrix_set_ix(0,1);
    }
    }
}
